package pl.edu.utp.ga.genotypes;

import java.util.ArrayList;
import java.util.List;

import pl.edu.utp.ga.genes.FloatingGene;
import pl.edu.utp.ga.interfaces.Calculation;
import pl.edu.utp.ga.interfaces.Gene;
import pl.edu.utp.ga.interfaces.Genotype;

public class NumberGenotype extends BasicGenotype{
	
	public NumberGenotype(){
		super();
	}
	
	public NumberGenotype(int size){
		super(size);
	}
	
	public NumberGenotype(ArrayList<Gene<?>> genes){
		super(genes);
	}
	
	@Override
	public void generate() {
		for(int i=0;i<size;i++){
			FloatingGene gene = null;

			if(genesRanges != null){
				try{
					gene = new FloatingGene(genesRanges.get(i));
				}catch(ArrayIndexOutOfBoundsException ex){
					gene = new FloatingGene();
				}
			} else{
				gene = new FloatingGene();
			}
			if(genes.size() < size){
				genes.add(gene);
			} else{
				genes.set(i, gene);
			}
		}
	}

	@SuppressWarnings("rawtypes")
	@Override
	public ArrayList<Genotype> cross(List<? extends Gene> secondParentGenes) {
		
		ArrayList<Genotype> genotypes = new ArrayList<Genotype>();
		int splitPoint = getSplitPoint();
		
		ArrayList<Gene<?>> firstChildGenes = new ArrayList<>();
		ArrayList<Gene<?>> secondChildGenes = new ArrayList<>();
		
		for(int i=0;i<size;i++){
			if(i < splitPoint){
				FloatingGene g1 = new FloatingGene(((Double)genes.get(i).get()).doubleValue());
				FloatingGene g2 = new FloatingGene(((Double)secondParentGenes.get(i).get()).doubleValue());
				
				firstChildGenes.add(g1);
				secondChildGenes.add(g2);
			}else{
				FloatingGene g1 = new FloatingGene(((Double)genes.get(i).get()).doubleValue());
				FloatingGene g2 = new FloatingGene(((Double)secondParentGenes.get(i).get()).doubleValue());
				
				secondChildGenes.add(g1);
				firstChildGenes.add(g2);
			}
		}	
		genotypes.add(new NumberGenotype(firstChildGenes));
		genotypes.add(new NumberGenotype(secondChildGenes));
		
		return genotypes;
	}
	
	@Override
	public void mutate(){
		int genePosition = genePosition();
		double mutation = getMutation();
		FloatingGene gene = (FloatingGene)genes.get(genePosition);
		gene.mutate(mutation);
	}
	
	private double getMutation(){
		return random.nextDouble()/10;
	}
	
	@Override
	public double rate(Calculation calculation){
		double[] geneValues = new double[genes.size()];
		for(int i=0; i<genes.size(); i++){
			FloatingGene gene = (FloatingGene)genes.get(i);
			geneValues[i] = gene.get();
		}
		return calculation.calculate(geneValues);
	}
}